package com.kmxd.ams.core.oss.template.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.kmxd.ams.core.common.enums.OssEnum;
import com.kmxd.ams.core.oss.bo.OssFile;
import com.kmxd.ams.core.oss.properties.OssProperties;
import com.kmxd.ams.core.oss.template.IOssSvc;
import com.kmxd.ams.core.util.SecureUtils;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * oos本地文件实现
 *
 * @author ZuoLG
 */
@Slf4j
@Service("local")
@RequiredArgsConstructor
public class LocalOssSvcImpl implements IOssSvc {

  /** 配置文件对象 */
  @Autowired private OssProperties ossProperties;

  @Value("${spring.application.name:ams}")
  private String appName;

  /**
   * 获取文件分隔符
   *
   * <p>此处使用linux分隔符统一
   *
   * @return
   */
  @Override
  public String separator() {
    return "/";
  }

  /**
   * 路径转换
   *
   * @param path
   * @return
   */
  private String toUnixPath(String path) {
    return separatorsToUnix(path);
  }

  /**
   * common io包中方法
   *
   * @param path
   * @return
   */
  public static String separatorsToUnix(String path) {
    return path != null && path.indexOf(92) != -1 ? path.replace('\\', '/') : path;
  }

  /**
   * 根据枚举获取文件根路径
   *
   * @param ossEnum
   * @return
   */
  private String getRootPath(OssEnum ossEnum) {
    Map<String, String> paths = ossProperties.getPaths();
    String path = MapUtil.getStr(paths, ossProperties.getDefPath());
    if (ossEnum.getType().equalsIgnoreCase(OssEnum.collect.getType())) {
      return path + ossProperties.getCollect();
    }
    if (ossEnum.getType().equalsIgnoreCase(OssEnum.manage.getType())) {
      return path + ossProperties.getManage();
    }
    if (ossEnum.getType().equalsIgnoreCase(OssEnum.temp.getType())) {
      return path + ossProperties.getTemp();
    }
    if (ossEnum.getType().equalsIgnoreCase(OssEnum.attachment.getType())) {
      return path + ossProperties.getAttachment();
    }
    if (ossEnum.getType().equalsIgnoreCase(OssEnum.backup.getType())) {
      return path + ossProperties.getBackup();
    }

    return path + ossProperties.getAttachment();
  }

  @Override
  public OssFile upload(MultipartFile file, OssEnum ossEnum, String path) throws Exception {
    return upload(file, ossEnum, path, null);
  }

  @Override
  public OssFile upload(File file, OssEnum ossEnum, String path) throws Exception {
    return upload(file, ossEnum, path, null);
  }

  @Override
  public OssFile upload(MultipartFile file, OssEnum ossEnum, String path, String newFileName)
      throws Exception {
    // 获取文件名
    String rooPath = getRootPath(ossEnum);
    String orgName =
        DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN)
            + file.getOriginalFilename();
    orgName = StrUtil.isNotBlank(newFileName) ? newFileName : orgName;
    path = StrUtil.isNotBlank(path) ? path : "";
    // filePath添加多盘目录及
    String filePath =
        separator()
            + ossProperties.getDefPath()
            + (path.startsWith(separator()) ? path : separator() + path)
            + separator()
            + orgName;
    FileUtil.mkdir(
        rooPath
            + separator()
            + ossProperties.getDefPath()
            + (path.startsWith(separator()) ? path : separator() + path));

    FileCopyUtils.copy(file.getBytes(), FileUtil.file(rooPath + filePath));
    OssFile ossFile = new OssFile();
    try {
      String md5 = SecureUtils.md5(FileUtil.file(rooPath + filePath));
      String sm3 = SecureUtils.sm3(FileUtil.file(rooPath + filePath));
      ossFile.setMd5(md5);
      ossFile.setSm3(sm3);
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      log.error("获取文件MD5异常。");
    }
    ossFile.setName(orgName);
    ossFile.setFileSize(file.getSize());
    ossFile.setPath(toUnixPath(filePath));
    ossFile.setRootPath(toUnixPath(rooPath));
    ossFile.setExt(FileUtil.extName(orgName));

    return ossFile;
  }

  @Override
  public OssFile upload(File file, OssEnum ossEnum, String path, String newFileName)
      throws Exception {
    // 获取文件名
    String rooPath = getRootPath(ossEnum);
    String orgName =
        DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN) + file.getName();
    orgName = StrUtil.isNotBlank(newFileName) ? newFileName : orgName;
    path = StrUtil.isNotBlank(path) ? path : "";
    String filePath =
        separator()
            + ossProperties.getDefPath()
            + (path.startsWith(separator()) ? path : separator() + path)
            + separator()
            + orgName;

    FileUtil.mkdir(rooPath + (path.startsWith(separator()) ? path : separator() + path));

    FileCopyUtils.copy(file, FileUtil.file(rooPath + filePath));
    String md5 = SecureUtils.md5(FileUtil.file(rooPath + filePath));
    OssFile ossFile = new OssFile();
    ossFile.setMd5(md5);
    ossFile.setName(orgName);
    ossFile.setFileSize(FileUtil.size(file));
    ossFile.setPath(toUnixPath(filePath));
    ossFile.setRootPath(toUnixPath(rooPath));
    ossFile.setExt(FileUtil.extName(orgName));

    return ossFile;
  }

  @Override
  public boolean delete(String path) {
    return FileUtil.del(path);
  }

  @Override
  public String rename(String path, String newName) {
    if (StrUtil.equals(path, newName)) {
      return toUnixPath(newName);
    }
    // 使用复制的方式，然后再删除原始文件
    if (FileUtil.exist(path)) {
      File srcFile = FileUtil.file(path);
      FileUtil.copy(srcFile, FileUtil.file(newName), true);
      // 删除原始文件
      FileUtil.del(srcFile);
    }
    return toUnixPath(newName);
  }

  @Override
  public File getFile(String path) {
    return FileUtil.file(path);
  }

  @Override
  public File copy(String src, String target) {
    // 如果文件不存在，不进行复制操作，不然会报文件不存在
    if (!exist(src)) {
      return null;
    }
    return FileUtil.copy(src, target, true);
  }

  @Override
  public InputStream getFileInputStream(String path) {
    return FileUtil.getInputStream(FileUtil.file(path));
  }

  @Override
  public String checkFileMd5(String md5, String fileName) {
    return null;
  }

  @Override
  public OssFile exportZip(List<OssFile> paths) {
    String dt = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN);
    OssFile ossFile = new OssFile();
    ossFile.setExt("zip");
    ossFile.setName(dt + "." + ossFile.getExt());
    Date date = DateUtil.date();
    // 构建临时下载zip包文件
    String fileName =
        getRootPath(OssEnum.temp)
            + separator()
            + DateUtil.year(date)
            + separator()
            + DateUtil.month(date)
            + ossFile.getName();
    File zipFile = FileUtil.file(fileName);

    List<File> fileList = Lists.newArrayList();
    // 循环
    for (int i = 0; i < paths.size(); i++) {
      OssFile temOssFile = paths.get(i);
      File fileTmp = FileUtil.file(temOssFile.getRootPath() + temOssFile.getPath());
      if (fileTmp.exists()) {
        fileList.add(fileTmp);
      }
    }
    if (!fileList.isEmpty()) {
      // 打包数据
      File[] files = fileList.toArray(new File[fileList.size()]);
      ZipUtil.zip(zipFile, false, files);
      ossFile.setFile(zipFile);
    }
    return ossFile;
  }

  @Override
  public boolean exist(String path) {
    return FileUtil.exist(path);
  }

  @Override
  public boolean mkdir(String dest) {
    FileUtil.mkdir(dest);
    return true;
  }

  @Override
  public String getSystemTempPath() {
    String tmpPath = FileUtil.getTmpDirPath() + separator() + appName;
    if (!FileUtil.exist(tmpPath)) {
      FileUtil.mkdir(tmpPath);
    }
    return tmpPath;
  }
}
